package com.canbot.u05.utils;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Environment;
import android.os.Looper;
import android.support.v4.util.ArrayMap;
import android.util.Log;

import com.canbot.u05.R;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;

import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class CrashHandler implements UncaughtExceptionHandler {

        public static final String TAG = "CrashHandler";

        // 系统默认的UncaughtException处理类
        private Thread.UncaughtExceptionHandler mDefaultHandler;

        // CrashHandler实例
        private static CrashHandler instance;

        // 程序的Context对象
        private Context mContext;

        // 用来存储设备信息和异常信息
        private ArrayMap<String, String> infos = new ArrayMap<String, String>();

        // 用于格式化日期,作为日志文件名的一部分
        private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.CHINA);

        /**
         * 保证只有一个CrashHandler实例.
         */
        private CrashHandler() {
        }

        /**
         * 获取CrashHandler实例 ,单例模式.
         */
        public static CrashHandler getInstance() {
                if (instance == null) {
                        instance = new CrashHandler();
                }
                return instance;
        }

        /**
         * 初始化 .
         */
        public void init(Context context) {
                mContext = context;
                // 获取系统默认的UncaughtException处理器
                mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
                // 设置该CrashHandler为程序的默认处理器
                Thread.setDefaultUncaughtExceptionHandler(this);
        }

        /**
         * 当UncaughtException发生时会转入该函数来处理 .
         */
        @Override
        public void uncaughtException(Thread thread, Throwable ex) {
                if (!handleException(ex) && mDefaultHandler != null) {
                        // 如果用户没有处理则让系统默认的异常处理器来处理
                        Log.e(TAG, "uncaughtException----if");
                        mDefaultHandler.uncaughtException(thread, ex);
                }
                else {
                        Log.e(TAG, "uncaughtException----else");
                        try {
                                Thread.currentThread().wait();
                        }
                        catch (InterruptedException e) {
                                e.printStackTrace();
                        }
//			// 退出程序
//			android.os.Process.killProcess(android.os.Process.myPid());
//			System.exit(1);
                }
        }

        /**
         * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
         *
         * @param ex
         * @return true:如果处理了该异常信息;否则返回false.
         */
        private boolean handleException(Throwable ex) {
                if (ex == null) {
                        return false;
                }
                // 收集设备参数信息
                collectDeviceInfo(mContext);
                // 使用Toast来显示异常信息
                new Thread() {
                        @Override
                        public void run() {
                                Looper.prepare();
                                Log.e(TAG, "handleException----");
                                ToastTools.newInstance(mContext).showText(mContext.getString(R.string.program_out_order));

                                Looper.loop();
                        }
                }.start();
                // 保存日志文件
                saveCatchInfo2File(ex);
                return true;
        }

        /**
         * 收集设备参数信息 .
         *
         * @param ctx
         */
        public void collectDeviceInfo(Context ctx) {
                try {
                        PackageManager pm = ctx.getPackageManager();
                        PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);
                        if (pi != null) {
                                String versionName = pi.versionName == null ? "null" : pi.versionName;
                                String versionCode = pi.versionCode + "";
                                infos.put("versionName", versionName);
                                infos.put("versionCode", versionCode);
                        }
                }
                catch (NameNotFoundException e) {
                        Log.e(TAG, "an error occured when collect package info", e);
                }
                Field[] fields = Build.class.getDeclaredFields();
                for (Field field : fields) {
                        try {
                                field.setAccessible(true);
                                infos.put(field.getName(), field.get(null).toString());
                                Log.i(TAG, field.getName() + " : " + field.get(null));
                        }
                        catch (Exception e) {
                                Log.e(TAG, "an error occured when collect crash info", e);
                        }
                }
        }

        private String getFilePath() {
//                String file_dir = mContext.getFilesDir().getPath() + "/U05CrashLog/";
//                boolean isSDCardExist = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
//                boolean isRootDirExist = Environment.getExternalStorageDirectory().exists();
//                if (isSDCardExist && isRootDirExist) {
                return Environment.getExternalStorageDirectory() + "/ai/CrashLog/";
//                }
//                return file_dir;
        }

        /**
         * 保存错误信息到文件中
         *
         * @param ex
         * @return 返回文件名称, 便于将文件传送到服务器
         */
        private String saveCatchInfo2File(Throwable ex) {
                final StringBuffer sb = new StringBuffer();
                for (Map.Entry<String, String> entry : infos.entrySet()) {
                        String key = entry.getKey();
                        String value = entry.getValue();
                        sb.append(key + "=" + value + "\n");
                }
                Writer writer = new StringWriter();
                PrintWriter printWriter = new PrintWriter(writer);
                ex.printStackTrace(printWriter);
                Throwable cause = ex.getCause();
                while (cause != null) {
                        cause.printStackTrace(printWriter);
                        cause = cause.getCause();
                }
                printWriter.close();
                String result = writer.toString();
                sb.append(result);
                try {
                        long timestamp = System.currentTimeMillis();
                        String time = formatter.format(new Date());
                        String fileName = "crash-" + time + "-" + timestamp + ".log";
                        String file_dir = getFilePath();
                        // if
                        // (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
                        // {
                        File dir = new File(file_dir);
                        if (!dir.exists()) {
                                dir.mkdirs();
                        }
                        File file = new File(file_dir + fileName);
                        if (!file.exists()) {
                                file.createNewFile();
                        }
                        FileOutputStream fos = new FileOutputStream(file);
                        fos.write(sb.toString().getBytes());
                        // 发送给开发人员
                        fos.close();
                        sendCrashLog2PM(sb.toString());
                        return fileName;
                }
                catch (IOException e) {
                        e.printStackTrace();
                        Log.e(TAG, "an error occured while writing file...", e);
                }
                catch (InterruptedException e) {
                        e.printStackTrace();
                        Log.e(TAG, "an error occured while writing file...", e);
                }
                return null;
        }

        /**
         * 将捕获的导致崩溃的错误信息发送给开发人员 . 目前只将log日志保存在sdcard 和输出到LogCat中，并未发送给后台。
         *
         * @throws InterruptedException
         * @throws IOException
         * @throws MessagingException
         */
        private void sendCrashLog2PM(final String data) throws InterruptedException {
                Logger.e(TAG, "send email================!"+data);
                // 退出程序
                android.os.Process.killProcess(android.os.Process.myPid());
                System.exit(1);
//                Thread thread = new Thread() {
//                        public void run() {
//                                String localMacAddress = getLocalMacAddressFromIp(mContext);
//                                sendEmail("V2版本  U05 com.uurobot.voicesrc 奔溃信息,版本号： " + infos.get("versionCode") + ",  MAC: " + localMacAddress,
//                                        data);
//                        }
//
//                };
//                thread.start();
//                thread.join();
        }

        private void sendEmail(String title, String content) {
                Logger.e(TAG, content);
                Logger.e(TAG, "sendEmail ================ start");
                String username = "andy.he@uurobot.cn";
//                String username4 = "mingping.zhang@uurobot.cn";
                String password = "hehui0321Ass";
                String sendhost = "smtp.exmail.qq.com";
                Properties props = new Properties();
                props.put("mail.smtp.host", sendhost);// 存储发送邮件服务器的信息
                props.put("mail.smtp.auth", "true");// 同时通过验证
                // 基本的邮件会话
                Session session = Session.getInstance(props);
                session.setDebug(false);// 设置调试标志
                // 构造信息体
                MimeMessage message = new MimeMessage(session);
                Address fromAddress = null;
                Logger.e(TAG, "sendEmail ================ Address fromAddress = null;");
                try {
                        fromAddress = new InternetAddress(username);
                        message.setFrom(fromAddress);

                        Address toAddress = new InternetAddress(username);
                        Address toAddress2 = new InternetAddress("jiao.wang@uurobot.cn");
                        Address toAddress3 = new InternetAddress("liu.tao@uurobot.cn");
//                        Address toAddress4 = new InternetAddress(username4);
//                        Address toAddress5 = new InternetAddress("li.jie@uurobot.cn");
                        message.addRecipient(Message.RecipientType.TO, toAddress);

//                        for(String a: Config.RECIPIENTS){
//
//                                message.addRecipient(Message.RecipientType.TO, new InternetAddress(a));
//
//                        }


                        message.addRecipient(Message.RecipientType.TO, toAddress2);
//                        message.addRecipient(Message.RecipientType.TO, toAddress4);
//                        message.addRecipient(Message.RecipientType.TO, toAddress5);
                        message.addRecipient(Message.RecipientType.TO, toAddress3);
                        message.setSubject(title);// 设置信件的标题
                        message.setText(content);// 设置信件内容
                        Logger.e(TAG, "sendEmail ================ message.setText(content)");
                        message.saveChanges(); // implicit with send()//存储有信息
                        Logger.e(TAG, "sendEmail ================message.saveChanges();;");
                        // send e-mail message
                        Transport transport = null;
                        transport = session.getTransport("smtp");
                        Logger.e(TAG, "transport = session.getTransport(\"smtp\")");
                        transport.connect(sendhost, username, password);
                        Logger.e(TAG, "transport.connect(sendhost, username, password)");
                        transport.sendMessage(message, message.getAllRecipients());
                        transport.close();
                        Logger.e(TAG, "sendEmail ================ transport.close();");
                }
                catch (MessagingException e) {
                        e.printStackTrace();
                        Logger.e(TAG, "sendEmail ================ MessagingException" + e.toString());
                }
                Logger.e(TAG, "sendEmail ================ success");
//		// 退出程序
                android.os.Process.killProcess(android.os.Process.myPid());
                System.exit(1);
        }

        //        // 获取本机的MAC地址
//        public String getLocalMacAddress(Context context) {
//                if (com.uurobot.common.utils.NetworkUtils.checkNetworkConnection(context)) {
//                        WifiManager wifi = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
//                        WifiInfo info = wifi.getConnectionInfo();
//                        String macAddress = info.getMacAddress();
//                        String mac = macAddress.replace(":", "");
//                        return mac;
//                }
//                return null;
//
//        }
        // 获取本机的MAC地址
        public static String getLocalMacAddressFromIp(Context context) {
                String mac_s = "";
                try {
                        byte[] mac;
                        NetworkInterface ne = NetworkInterface.getByInetAddress(InetAddress.getByName(getLocalIpAddress()));
                        mac = ne.getHardwareAddress();
                        mac_s = byte2hex(mac);
                }
                catch (Exception e) {
                        e.printStackTrace();
                }
                return mac_s;
        }

        public static String byte2hex(byte[] b) {
                StringBuffer hs = new StringBuffer(b.length);
                String stmp = "";
                int len = b.length;
                for (int n = 0; n < len; n++) {
                        stmp = Integer.toHexString(b[n] & 0xFF);
                        if (stmp.length() == 1)
                                hs = hs.append("0").append(stmp);
                        else {
                                hs = hs.append(stmp);
                        }
                }
                return String.valueOf(hs);
        }


        public static String getLocalIpAddress() {
                try {
                        String ipv4;
                        List<NetworkInterface> nilist = Collections.list(NetworkInterface.getNetworkInterfaces());
                        for (NetworkInterface ni : nilist) {
                                List<InetAddress> ialist = Collections.list(ni.getInetAddresses());
                                for (InetAddress address : ialist) {
                                        if (!address.isLoopbackAddress() && address instanceof Inet4Address) {
                                                ipv4 = address.getHostAddress();
                                                Logger.e("ipv4", ipv4);
                                                if (!"192.168.12.1".equals(ipv4)) {
                                                        return ipv4;
                                                }
                                        }
                                }
                        }
                }
                catch (SocketException ex) {
                        ex.printStackTrace();
                }
                return null;
        }

}